<template>
  <div class="v-table-views v-table-class" :style="{'width': internalWidth+'px', 'height': getTableHeight+'px','background-color':tableBgColor}">
    <div class="v-table-rightview" :style="{'width': viewWidth+'px'}">
      <!--列头-->
      <div class="v-table-header v-table-title-class" :style="{'width': (viewWidth-1)+'px','background-color':titleBgColor}">
        <div class="v-table-header-inner" style="display: block;">
          <table class="v-table-htable" border="0" cellspacing="0" cellpadding="0">
            <tbody>
              <template>
                <tr class="v-table-header-row">
                  <td v-for="(col,colIndex) in visiableColumns" :class="[col.titleCellClassName]">
                    <div :class="['v-table-title-cell',showVerticalBorder?'vertical-border':'',showHorizontalBorder?'horizontal-border':'']" :style="{'width':col.width+'px','height':titleRowHeight+'px','text-align':col.titleAlign}">
                      <span class="table-title">
                        <span v-html="col.title"></span>
                      </span>
                    </div>
                  </td>
                </tr>
                <!-- 筛选列 -->
                <tr v-if="isFilter" class="v-table-header-row">
                  <td v-for="(col,colIndex) in visiableColumns" :class="[col.titleCellClassName]">
                    <div :class="['v-table-title-cell',showVerticalBorder?'vertical-border':'',showHorizontalBorder?'horizontal-border':'']" :style="{'width':col.width+'px','height':titleRowHeight+'px','text-align':col.titleAlign}">
                      <filter-header :dataFilterRules="dataFilterRules" :column="col" :clearFilterFlag="clearFilterFlag" @on-filter-change="onFilterChange" @on-filter-delete="onFilterDelete"></filter-header>
                    </div>
                  </td>
                </tr>
              </template>
            </tbody>
          </table>
        </div>
      </div>
      <!--列内容-->
      <div :class="['v-table-body v-table-body-class',vTableRightBody]" :style="{'width': viewWidth+'px', 'height': bodyViewHeight+'px'}">
        <table class="v-table-btable" cellspacing="0" cellpadding="0" border="0">
          <tbody>
            <tr :key="rowIndex" v-for="(item,rowIndex) in internalTableData" class="v-table-row" :style="[trBgColor(rowIndex+1)]">
              <td v-for="(col,colIndex) in visiableColumns" :key="colIndex" :class="[setColumnCellClassName(rowIndex,col.field,item)]">
                <!--不存在列合并-->
                <div :class="['v-table-body-cell',showVerticalBorder ? 'vertical-border':'',showHorizontalBorder?'horizontal-border':'']" :style="{'width':col.width+'px','height': rowHeight+'px','line-height':rowHeight+'px','text-align':col.columnAlign}" :title="col.overflowTitle ?  overflowTitle(item,col) :''" @click.stop="onCellClick(rowIndex,item,col);cellEditClick($event,col.isEdit,item,col.field,rowIndex)">
                  <span v-if="typeof col.render ==='function'">
                    <expand :field="col.field ? col.field : ''" :row="item" :render="col.render" :index="rowIndex"></expand>
                  </span>
                  <span v-else>
                    {{item[col.field]}}
                  </span>
                </div>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>

    <table-empty v-if="isTableEmpty" :width="internalWidth" :total-columns-width="totalColumnsWidth" :content-height="errorContentHeight" :title-height="getTotalColumnsHeight()" :error-content="errorContent" :is-loading="isLoading"></table-empty>

    <loading v-if="isLoading" :loading-content="loadingContent" :title-row-height="titleRowHeight" :columns="visiableColumns"></loading>
  </div>
</template>

<script>
import classesMixin from "./classes-mixin.js";
import scrollControlMixin from "./scroll-control-mixin.js";
import tableResizeMixin from "./table-resize-mixin.js";
import tableEmptyMixin from "./table-empty-mixin.js";
import cellEditMixin from "./cell-edit-mixin.js";
import scrollBarControlMixin from "./scroll-bar-control-mixin.js";
import tableRowMouseEventsMixin from "./table-row-mouse-events-mixin";
import expand from "./expand.js";

import utils from "@/utils/utils.js";
import deepClone from "@/utils/deepClone.js";

import tableEmpty from "./table-empty.vue";
import loading from "./table-loading.vue";

import filterHeader from "./table-filter-header";
export default {
  name: "v-table",
  mixins: [
    classesMixin,
    tableResizeMixin,
    scrollControlMixin,
    tableRowMouseEventsMixin,
    tableEmptyMixin,
    cellEditMixin,
    scrollBarControlMixin
  ],
  components: { filterHeader, tableEmpty, loading, expand },
  data() {
    return {
      // 本地列表数据
      internalTableData: [],
      // 本地宽度
      internalWidth: 0,
      // 本地高度
      internalHeight: 0,
      // 本地列数据
      internalColumns: [],
      // 可见列
      visiableColumns: [],
      errorMsg: " V-Table error: ",
      // 最大宽度（当width:'max'时）
      maxWidth: 5000,
      hasBindScrollEvent: false, // 是否绑定了滚动事件（防止多次注册）
      // 筛选参数
      filterParam: []
    };
  },
  props: {
    width: [Number, String],
    minWidth: {
      type: Number,
      default: 50
    },
    height: {
      type: Number,
      require: false
    },
    minHeight: {
      type: Number,
      default: 50
    },
    titleRowHeight: {
      type: Number,
      default: 38
    },
    // 开启筛选
    isFilter: {
      type: Boolean,
      default: false
    },
    // 开启清空筛选
    clearFilterFlag: {
      type: Boolean,
      default: false
    },
    // 垂直自适应偏移量
    verticalResizeOffset: {
      type: Number,
      default: 50
    },

    tableBgColor: {
      type: String,
      default: "#fff"
    },

    // 表头背景颜色
    titleBgColor: {
      type: String,
      default: "#fff"
    },

    // 奇数行颜色
    oddBgColor: {
      type: String,
      default: ""
    },
    // 偶数行颜色
    evenBgColor: {
      type: String,
      default: ""
    },
    // 内容行高
    rowHeight: {
      type: Number,
      default: 40
    },
    columns: {
      type: Array,
      require: true
    },
    // 特殊表头
    titleRows: {
      type: Array,
      require: true,
      default: function() {
        return [];
      }
    },
    tableData: {
      type: Array,
      require: true,
      default: function() {
        return [];
      }
    },
    dataFilterRules: {
      type: Object,
      default: function() {
        return {};
      }
    },
    // 分页序号
    pagingIndex: Number,
    // 没数据时的html
    errorContent: {
      type: String,
      default: "暂无数据"
    },
    // 没数据时内容区域高度
    errorContentHeight: {
      type: Number,
      default: 50
    },
    // 是否正在加载,为false 则会显示错误信息（如果加载时间较长，最好设置为true,数据返回后设置为false）
    isLoading: {
      type: Boolean,
      default: false
    },
    loadingContent: {
      type: String,
      default:
        '<span><i class="v-icon-spin5 animate-loading-23" style="font-size: 28px;opacity:0.6;"></i></span>'
    },
    // 不设置则没有hover效果
    rowHoverColor: {
      type: String
    },
    rowClickColor: {
      type: String
    },
    showVerticalBorder: {
      type: Boolean,
      default: true
    },
    showHorizontalBorder: {
      type: Boolean,
      default: true
    },
    // 表体单元格样式回调
    columnCellClassName: Function,
    // 行点击回调
    onRowClick: Function,
    // 单元格编辑完成回调
    cellEditDone: Function,
    // 单元格点击回调
    cellClickDone: Function
  },
  computed: {
    // 获取表格高度
    getTableHeight() {
      return this.isTableEmpty ? this.tableEmptyHeight : this.internalHeight;
    },
    // 区域宽度
    viewWidth() {
      return this.internalWidth - 2;
    },
    // 区域高度
    bodyViewHeight() {
      var result;
      if (this.isFilter) {
        result = this.internalHeight - this.titleRowHeight * 2;
      } else {
        result = this.internalHeight - this.titleRowHeight;
      }

      return result;
    },

    // 所有列的总宽度
    totalColumnsWidth() {
      return this.visiableColumns.reduce(function(total, curr) {
        return curr.width ? total + curr.width : total;
      }, 0);
    }
  },
  methods: {
    // custom columns component event
    customCompFunc(params) {
      this.$emit("on-custom-comp", params);
    },

    // 行颜色
    trBgColor(num) {
      if (
        (this.evenBgColor && this.evenBgColor.length > 0) ||
        (this.oddBgColor && this.oddBgColor.length > 0)
      ) {
        return num % 2 === 0
          ? { "background-color": this.evenBgColor }
          : { "background-color": this.oddBgColor };
      }
    },

    // 设置 column 列的样式
    setColumnCellClassName(rowIndex, field, rowData) {
      return (
        this.columnCellClassName &&
        this.columnCellClassName(rowIndex, field, rowData)
      );
    },

    // 获取每个表头列的宽度
    titleColumnWidth(fields) {
      var result = 0;
      if (Array.isArray(fields)) {
        var matchItems = this.visiableColumns.filter((item, index) => {
          return fields.some(x => x === item.field);
        });

        result = matchItems.reduce((total, curr) => total + curr.width, 0);
      } else {
        console.error(
          this.errorMsg + "the fields attribute must be a array in titleRows"
        );
      }
      return result;
    },

    // 获取每个表头列的高度
    titleColumnHeight(rowspan) {
      if (rowspan && rowspan > 0) {
        return this.titleRowHeight * rowspan;
      } else {
        return this.titleRowHeight;
      }
    },

    // 超出的title提示
    overflowTitle(row, col) {
      var result = "";
      if (typeof col.formatter === "function") {
        var val = col.formatter(row, -1);
        // 如果是html 不处理
        if (utils.isHtml(val)) {
          result = "";
        } else {
          result = val;
        }
      } else {
        result = row[col.field];
      }
      return result;
    },

    // 获取所有列的总高度
    getTotalColumnsHeight() {
      var titleTotalHeight = this.titleRowHeight;

      if (this.isFilter) titleTotalHeight += this.titleRowHeight;

      return (
        titleTotalHeight + this.internalTableData.length * this.rowHeight + 1
      );
    },

    // 初始化width
    initTableWidth() {
      this.internalWidth = this.maxWidth;
    },

    // 当宽度设置 && 非固定列未设置宽度时（列自适应）初始化列集合
    initColumns() {
      this.internalHeight = this.height;

      this.internalColumns = Array.isArray(this.columns)
        ? deepClone(this.columns)
        : [];

      this.visiableColumns = this.internalColumns.filter(
        item => item.visiable === true || typeof item.visiable == "undefined"
      );

      this.initResizeColumns();

      this.initTableWidth();

      var self = this,
        widthCountCheck = 0;

      if (self.internalWidth && self.internalWidth > 0) {
        self.visiableColumns.map(function(item) {
          if (!(item.width && item.width > 0)) {
            widthCountCheck++;
            console.error(
              self.errorMsg +
                "If you are using the isHorizontalResize property,Please set the value for each column's width"
            );
          }
        });
        self.resize();
      }

      if (widthCountCheck > 1) {
        console.error(this.errorMsg + "Only allow one column is not set width");
      }
    },

    // 当没设置宽度和高度时动态计算
    initView() {
      // 当没有设置宽度计算总宽度
      if (!(this.internalWidth && this.internalWidth > 0)) {
        if (this.columns && this.columns.length > 0) {
          this.internalWidth = this.columns.reduce(
            (total, curr) => total + curr.width,
            0
          );
        }
      }

      var totalColumnsHeight = this.getTotalColumnsHeight();

      // 当没有设置高度时计算总高度 || 设置的高度大于所有列高度之和时
      if (
        !(this.height && this.height > 0) ||
        this.height > totalColumnsHeight
      ) {
      } else if (this.height <= totalColumnsHeight) {
        this.internalHeight = this.height;
      }
    },

    initInternalTableData() {
      return Array.isArray(this.tableData) ? deepClone(this.tableData) : [];
    },

    // 对外暴露（隐藏显示切换时）
    resize(time) {
      let t = 50;
      var resizeInterval = setInterval(x => {
        this.tableResize();
      }, t);
      let timer = t * 2;
      if (time) timer = time + t;
      // fixed bug in IE9 #17
      setTimeout(() => {
        window.clearInterval(resizeInterval);
      }, timer);
    },

    onFilterChange(filterOpt) {
      let filterParam = this.filterParam;
      let findIndex = -1;
      for (let index in filterParam) {
        let param = filterParam[index];
        if (param.field == filterOpt.field) {
          findIndex = index;
          break;
        }
      }
      if (findIndex < 0) filterParam.push(filterOpt);
      else filterParam.splice(findIndex, 1, filterOpt);
      this.$emit("on-filter-change", filterParam);
    },
    onFilterDelete(field) {
      let filterParam = this.filterParam;
      let findIndex = -1;
      for (let index in filterParam) {
        let param = filterParam[index];
        if (param.field == field) {
          findIndex = index;
          break;
        }
      }
      if (findIndex > -1) {
        filterParam.splice(findIndex, 1);
        this.$emit("on-filter-change", filterParam);
      }
    }
  },
  created() {
    this.internalTableData = this.initInternalTableData(this.tableData);

    if (Array.isArray(this.columns) && this.columns.length > 0) {
      this.initColumns();
    }

    this.initView();
  },
  mounted() {
    this.setScrollbarWidth();

    this.tableResize();

    this.tableEmpty();

    if (Array.isArray(this.tableData) && this.tableData.length > 0) {
      this.scrollControl();
    }
  },
  watch: {
    // 重新更新列信息
    columns: {
      handler: function(newVal) {
        this.initColumns();
      },
      deep: true
    },
    // 重新覆盖复杂表头信息
    titleRows: {
      handler: function(newVal) {
        this.initColumns();
      },
      deep: true
    },

    // deep watch
    tableData: {
      handler: function(newVal) {
        this.internalTableData = this.initInternalTableData(newVal);

        this.tableEmpty();

        if (this.isTableEmpty) {
          this.hasBindScrollEvent = false;
        }

        if (Array.isArray(newVal) && newVal.length > 0) {
          this.initView();

          this.scrollControl();
        }

        this.resize();
      },
      deep: true
    }
  }
};
</script>